home *** CD-ROM | disk | FTP | other *** search
/ Maclife 157 / MACLIFE157-2001-09.ISO.7z / MACLIFE157-2001-09.ISO / Linux / MacOS Tools / Other / BootX 1.1.3 (for Old Mac OS) / Sources / lib / From MoreFiles / DirectoryCopy.c next >
Text File  |  2001-07-23  |  21KB  |  654 lines

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    DirectoryCopy: A robust, general purpose directory copy routine.
  5. **
  6. **    by Jim Luther, Apple Developer Technical Support Emeritus
  7. **
  8. **    File:        DirectoryCopy.c
  9. **
  10. **    Copyright ゥ 1992-1998 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  17. **    after having made changes. If you're going to re-distribute the source,
  18. **    we require that you make it clear in the source that the code was
  19. **    descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #include <Types.h>
  23. #include <Errors.h>
  24. #include <Memory.h>
  25. #include <Files.h>
  26. #include <Script.h>
  27.  
  28. #define    __COMPILINGMOREFILES
  29.  
  30. #include "MoreFiles.h"
  31. #include "MoreFilesExtras.h"
  32. #include "MoreDesktopMgr.h"
  33. #include "FileCopy.h"
  34. #include "DirectoryCopy.h"
  35.  
  36. /*****************************************************************************/
  37.  
  38. /* local constants */
  39.  
  40. enum
  41. {
  42.     dirCopyBigCopyBuffSize  = 0x00004000,
  43.     dirCopyMinCopyBuffSize  = 0x00000200
  44. };
  45.  
  46.  
  47. /*****************************************************************************/
  48.  
  49. /* local data structures */
  50.  
  51. /* The EnumerateGlobals structure is used to minimize the amount of
  52. ** stack space used when recursively calling CopyLevel and to hold
  53. ** global information that might be needed at any time. */
  54.  
  55. #if PRAGMA_ALIGN_SUPPORTED
  56. #pragma options align=mac68k
  57. #endif
  58. struct EnumerateGlobals
  59. {
  60.     Ptr            copyBuffer;            /* pointer to buffer used for file copy operations */
  61.     long        bufferSize;            /* the size of the copy buffer */
  62.     CopyErrProcPtr errorHandler;    /* pointer to error handling function */
  63.     CopyFilterProcPtr copyFilterProc; /* pointer to filter function */
  64.     OSErr        error;                /* temporary holder of results - saves 2 bytes of stack each level */
  65.     Boolean        bailout;            /* set to true to by error handling function if fatal error */
  66.     short        destinationVRefNum;    /* the destination vRefNum */
  67.     Str63        itemName;            /* the name of the current item */
  68.     CInfoPBRec    myCPB;                /* the parameter block used for PBGetCatInfo calls */
  69. };
  70. #if PRAGMA_ALIGN_SUPPORTED
  71. #pragma options align=reset
  72. #endif
  73.  
  74. typedef struct EnumerateGlobals EnumerateGlobals;
  75. typedef EnumerateGlobals *EnumerateGlobalsPtr;
  76.  
  77.  
  78. /* The PreflightGlobals structure is used to minimize the amount of
  79. ** stack space used when recursively calling GetLevelSize and to hold
  80. ** global information that might be needed at any time. */
  81.  
  82. #if PRAGMA_ALIGN_SUPPORTED
  83. #pragma options align=mac68k
  84. #endif
  85. struct PreflightGlobals
  86. {
  87.     OSErr            result;                /* temporary holder of results - saves 2 bytes of stack each level */
  88.     Str63            itemName;            /* the name of the current item */
  89.     CInfoPBRec        myCPB;                /* the parameter block used for PBGetCatInfo calls */
  90.  
  91.     unsigned long    dstBlksPerAllocBlk;    /* the number of 512 byte blocks per allocation block on destination */
  92.                                         
  93.     unsigned long    allocBlksNeeded;    /* the total number of allocation blocks needed  */
  94.  
  95.     unsigned long    tempBlocks;            /* temporary storage for calculations (save some stack space)  */
  96.     CopyFilterProcPtr copyFilterProc;    /* pointer to filter function */
  97. };
  98. #if PRAGMA_ALIGN_SUPPORTED
  99. #pragma options align=reset
  100. #endif
  101.  
  102. typedef struct PreflightGlobals PreflightGlobals;
  103. typedef PreflightGlobals *PreflightGlobalsPtr;
  104.  
  105. /*****************************************************************************/
  106.  
  107. /* static prototypes */
  108.  
  109. static    void    GetLevelSize(long currentDirID,
  110.                              PreflightGlobals *theGlobals);
  111.  
  112. static    OSErr    PreflightDirectoryCopySpace(short srcVRefNum,
  113.                                             long srcDirID,
  114.                                             short dstVRefNum,
  115.                                             CopyFilterProcPtr copyFilterProc,
  116.                                             Boolean *spaceOK);
  117.  
  118. static    void    CopyLevel(long sourceDirID,
  119.                           long dstDirID,
  120.                           EnumerateGlobals *theGlobals);
  121.                           
  122. /*****************************************************************************/
  123.  
  124. static    void    GetLevelSize(long currentDirID,
  125.                              PreflightGlobals *theGlobals)
  126. {
  127.     short    index = 1;
  128.     
  129.     do
  130.     {
  131.         theGlobals->myCPB.dirInfo.ioFDirIndex = index;
  132.         theGlobals->myCPB.dirInfo.ioDrDirID = currentDirID;    /* we need to do this every time */
  133.                                                             /* through, since GetCatInfo  */
  134.                                                             /* returns ioFlNum in this field */
  135.         theGlobals->result = PBGetCatInfoSync(&theGlobals->myCPB);
  136.         if ( theGlobals->result == noErr )
  137.         {
  138.             if ( (theGlobals->copyFilterProc == NULL) ||
  139.                  CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */
  140.             {
  141.                 /* Either there's no filter proc OR the filter proc says to use this item */
  142.                 if ( (theGlobals->myCPB.dirInfo.ioFlAttrib & ioDirMask) != 0 )
  143.                 {
  144.                     /* we have a directory */
  145.                     
  146.                     GetLevelSize(theGlobals->myCPB.dirInfo.ioDrDirID, theGlobals); /* recurse */
  147.                     theGlobals->result = noErr; /* clear error return on way back */
  148.                 }
  149.                 else
  150.                 {
  151.                     /* We have a file - add its allocation blocks to allocBlksNeeded. */
  152.                     /* Since space on Mac OS disks is always allocated in allocation blocks, */
  153.                     /* this takes into account rounding up to the end of an allocation block. */
  154.                     
  155.                     /* get number of 512-byte blocks needed for data fork */
  156.                     if ( ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen & 0x000001ff) != 0 )
  157.                     {
  158.                         theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9) + 1;
  159.                     }
  160.                     else
  161.                     {
  162.                         theGlobals->tempBlocks = (unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9;
  163.                     }
  164.                     /* now, calculate number of new allocation blocks needed for the data fork and add it to the total */
  165.                     if ( theGlobals->tempBlocks % theGlobals->dstBlksPerAllocBlk )
  166.                     {
  167.                         theGlobals->allocBlksNeeded += (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1;
  168.                     }
  169.                     else
  170.                     {
  171.                         theGlobals->allocBlksNeeded += theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk;
  172.                     }
  173.                     
  174.                     /* get number of 512-byte blocks needed for resource fork */
  175.                     if ( ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen & 0x000001ff) != 0 )
  176.                     {
  177.                         theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9) + 1;
  178.                     }
  179.                     else
  180.                     {
  181.                         theGlobals->tempBlocks = (unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9;
  182.                     }
  183.                     /* now, calculate number of new allocation blocks needed for the resource  fork and add it to the total */
  184.                     if ( theGlobals->tempBlocks % theGlobals->dstBlksPerAllocBlk )
  185.                     {
  186.                         theGlobals->allocBlksNeeded += (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1;
  187.                     }
  188.                     else
  189.                     {
  190.                         theGlobals->allocBlksNeeded += theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk;
  191.                     }
  192.                 }
  193.             }
  194.         }
  195.         ++index;
  196.     } while ( theGlobals->result == noErr );
  197. }
  198.  
  199. /*****************************************************************************/
  200.  
  201. static    OSErr    PreflightDirectoryCopySpace(short srcVRefNum,
  202.                                             long srcDirID,
  203.                                             short dstVRefNum,
  204.                                             CopyFilterProcPtr copyFilterProc,
  205.                                             Boolean *spaceOK)
  206. {
  207.     XVolumeParam pb;
  208.     OSErr error;
  209.     unsigned long dstFreeBlocks;
  210.     PreflightGlobals theGlobals;
  211.     
  212.     error = XGetVolumeInfoNoName(NULL, dstVRefNum, &pb);
  213.     if ( error == noErr )
  214.     {
  215.         /* Convert freeBytes to free disk blocks (512-byte blocks) */
  216.         dstFreeBlocks = (pb.ioVFreeBytes.hi << 23) + (pb.ioVFreeBytes.lo >> 9);
  217.         
  218.         /* get allocation block size (always multiple of 512) and divide by 512
  219.           to get number of 512-byte blocks per allocation block */
  220.         theGlobals.dstBlksPerAllocBlk = ((unsigned long)pb.ioVAlBlkSiz >> 9);
  221.         
  222.         theGlobals.allocBlksNeeded = 0;
  223.  
  224.         theGlobals.myCPB.dirInfo.ioNamePtr = theGlobals.itemName;
  225.         theGlobals.myCPB.dirInfo.ioVRefNum = srcVRefNum;
  226.         
  227.         theGlobals.copyFilterProc = copyFilterProc;
  228.         
  229.         GetLevelSize(srcDirID, &theGlobals);
  230.         
  231.         /* Is there enough room on the destination volume for the source file?                    */
  232.         /* Note:    This will work because the largest number of disk blocks supported            */
  233.         /*            on a 2TB volume is 0xffffffff and (allocBlksNeeded * dstBlksPerAllocBlk)    */
  234.         /*            will always be less than 0xffffffff.                                        */
  235.         *spaceOK = ((theGlobals.allocBlksNeeded * theGlobals.dstBlksPerAllocBlk) <= dstFreeBlocks);
  236.     }
  237.  
  238.     return ( error );
  239. }
  240.  
  241. /*****************************************************************************/
  242.  
  243. static    void    CopyLevel(long sourceDirID,
  244.                           long dstDirID,
  245.                           EnumerateGlobals *theGlobals)
  246. {
  247.     long currentSrcDirID;
  248.     long newDirID;
  249.     short index = 1;
  250.     
  251.     do
  252.     {    
  253.         /* Get next source item at the current directory level */
  254.         
  255.         theGlobals->myCPB.dirInfo.ioFDirIndex = index;
  256.         theGlobals->myCPB.dirInfo.ioDrDirID = sourceDirID;
  257.         theGlobals->error = PBGetCatInfoSync(&theGlobals->myCPB);        
  258.  
  259.         if ( theGlobals->error == noErr )
  260.         {
  261.             if ( (theGlobals->copyFilterProc == NULL) ||
  262.                  CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */
  263.             {
  264.                 /* Either there's no filter proc OR the filter proc says to use this item */
  265.  
  266.                 /* We have an item.  Is it a file or directory? */
  267.                 if ( (theGlobals->myCPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  268.                 {
  269.                     /* We have a directory */
  270.                     
  271.                     /* Create a new directory at the destination. No errors allowed! */
  272.                     theGlobals->error = DirCreate(theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName, &newDirID);
  273.                     if ( theGlobals->error == noErr )
  274.                     {
  275.                         /* Save the current source directory ID where we can get it when we come back
  276.                         ** from recursion land. */
  277.                         currentSrcDirID = theGlobals->myCPB.dirInfo.ioDrDirID;
  278.                         
  279.                         /* Dive again (copy the directory level we just found below this one) */
  280.                         CopyLevel(theGlobals->myCPB.dirInfo.ioDrDirID, newDirID, theGlobals);
  281.                         
  282.                         if ( !theGlobals->bailout )
  283.                         {
  284.                             /* Copy comment from old to new directory. */
  285.                             /* Ignore the result because we really don't care if it worked or not. */
  286.                             (void) DTCopyComment(theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, theGlobals->destinationVRefNum, newDirID, NULL);
  287.                             
  288.                             /* Copy directory attributes (dates, etc.) to newDirID. */
  289.                             /* No errors allowed */
  290.                             theGlobals->error = CopyFileMgrAttributes(theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, theGlobals->destinationVRefNum, newDirID, NULL, true);
  291.                             
  292.                             /* handle any errors from CopyFileMgrAttributes */
  293.                             if ( theGlobals->error != noErr )
  294.                             {
  295.                                 if ( theGlobals->errorHandler != NULL )
  296.                                 {
  297.                                     theGlobals->bailout =  CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, copyDirFMAttributesOp,
  298.                                                             theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL,
  299.                                                             theGlobals->destinationVRefNum, newDirID, NULL);
  300.                                 }
  301.                                 else
  302.                                 {
  303.                                     /* If you don't handle the errors with an error handler, */
  304.                                     /* then the copy stops here. */
  305.                                     theGlobals->bailout = true;
  306.                                 }
  307.                             }
  308.                         }
  309.                     }
  310.                     else    /* error handling for DirCreate */
  311.                     {
  312.                         if ( theGlobals->errorHandler != NULL )
  313.                         {
  314.                             theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, dirCreateOp,
  315.                                                         theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL,
  316.                                                         theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName);
  317.                         }
  318.                         else
  319.                         {
  320.                             /* If you don't handle the errors with an error handler, */
  321.                             /* then the copy stops here. */
  322.                             theGlobals->bailout = true;
  323.                         }
  324.                     }
  325.                     
  326.                     if ( !theGlobals->bailout )
  327.                     {
  328.                         /* clear error return on way back if we aren't bailing out */
  329.                         theGlobals->error = noErr;
  330.                     }
  331.                 }
  332.                 else
  333.                 {
  334.                     /* We have a file, so copy it */
  335.                     
  336.                     theGlobals->error = FileCopy(theGlobals->myCPB.hFileInfo.ioVRefNum,
  337.                                                  theGlobals->myCPB.hFileInfo.ioFlParID,
  338.                                                  theGlobals->itemName,
  339.                                                  theGlobals->destinationVRefNum,
  340.                                                  dstDirID,
  341.                                                  NULL,
  342.                                                  NULL,
  343.                                                  theGlobals->copyBuffer,
  344.                                                  theGlobals->bufferSize,
  345.                                                  false);
  346.                             
  347.                     /* handle any errors from FileCopy */
  348.                     if ( theGlobals->error != noErr )
  349.                     {
  350.                         if ( theGlobals->errorHandler != NULL )
  351.                         {
  352.                             theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, fileCopyOp,
  353.                                                     theGlobals->myCPB.hFileInfo.ioVRefNum, theGlobals->myCPB.hFileInfo.ioFlParID, theGlobals->itemName,
  354.                                                     theGlobals->destinationVRefNum, dstDirID, NULL);
  355.                             if ( !theGlobals->bailout )
  356.                             {
  357.                                 /* If the CopyErrProc handled the problem, clear the error here */
  358.                                 theGlobals->error = noErr;
  359.                             }
  360.                         }
  361.                         else
  362.                         {
  363.                             /* If you don't handle the errors with an error handler, */
  364.                             /* then the copy stops here. */
  365.                             theGlobals->bailout = true;
  366.                         }
  367.                     }
  368.                 }
  369.             }
  370.         }
  371.         else
  372.         {    /* error handling for PBGetCatInfo */
  373.             /* it's normal to get a fnfErr when indexing; that only means you've hit the end of the directory */
  374.             if ( theGlobals->error != fnfErr )
  375.             {
  376.                 if ( theGlobals->errorHandler != NULL )
  377.                 { 
  378.                     theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, getNextItemOp,
  379.                                             theGlobals->myCPB.dirInfo.ioVRefNum, sourceDirID, NULL, 0, 0, NULL);
  380.                     if ( !theGlobals->bailout )
  381.                     {
  382.                         /* If the CopyErrProc handled the problem, clear the error here */
  383.                         theGlobals->error = noErr;
  384.                     }
  385.                 }
  386.                 else
  387.                 {
  388.                     /* If you don't handle the errors with an error handler, */
  389.                     /* then the copy stops here. */
  390.                     theGlobals->bailout = true;
  391.                 }
  392.             }
  393.         }
  394.         ++index; /* prepare to get next item */
  395.     } while ( (theGlobals->error == noErr) && (!theGlobals->bailout) ); /* time to fall back a level? */
  396. }
  397.  
  398. /*****************************************************************************/
  399.  
  400. pascal    OSErr    FilteredDirectoryCopy(short srcVRefNum,
  401.                                       long srcDirID,
  402.                                       ConstStr255Param srcName,
  403.                                       short dstVRefNum,
  404.                                       long dstDirID,
  405.                                       ConstStr255Param dstName,
  406.                                       void *copyBufferPtr,
  407.                                       long copyBufferSize,
  408.                                       Boolean preflight,
  409.                                       CopyErrProcPtr copyErrHandler,
  410.                                       CopyFilterProcPtr copyFilterProc)
  411. {
  412.     EnumerateGlobals theGlobals;
  413.     Boolean    isDirectory;
  414.     OSErr    error;
  415.     Boolean ourCopyBuffer = false;
  416.     Str63    srcDirName, oldDiskName;
  417.     Boolean spaceOK;            
  418.     
  419.     /* Make sure a copy buffer is allocated. */
  420.     if ( copyBufferPtr == NULL )
  421.     {
  422.         /* The caller didn't supply a copy buffer so grab one from the application heap.
  423.         ** Try to get a big copy buffer, if we can't, try for a 512-byte buffer.
  424.         ** If 512 bytes aren't available, we're in trouble. */
  425.         copyBufferSize = dirCopyBigCopyBuffSize;
  426.         copyBufferPtr = NewPtr(copyBufferSize);
  427.         if ( copyBufferPtr == NULL )
  428.         {
  429.             copyBufferSize = dirCopyMinCopyBuffSize;
  430.             copyBufferPtr = NewPtr(copyBufferSize);
  431.             if ( copyBufferPtr == NULL )
  432.             {
  433.                 return ( memFullErr );
  434.             }
  435.         }
  436.         ourCopyBuffer = true;
  437.     }
  438.     
  439.     /* Get the real dirID where we're copying from and make sure it is a directory. */
  440.     error = GetDirectoryID(srcVRefNum, srcDirID, srcName, &srcDirID, &isDirectory);
  441.     if ( error != noErr )
  442.     {
  443.         goto ErrorExit;
  444.     }
  445.     if ( !isDirectory )
  446.     {
  447.         error = dirNFErr;
  448.         goto ErrorExit;
  449.     }
  450.     
  451.     /* Special case destination if it is the root parent directory. */
  452.     /* Since you can't create the root directory, this is needed if */
  453.     /* you want to copy a directory's content to a disk's root directory. */
  454.     if ( (dstDirID == fsRtParID) && (dstName == NULL) )
  455.     {
  456.         dstDirID = fsRtParID;
  457.         isDirectory = true;
  458.         error = noErr;
  459.     }
  460.     else
  461.     {
  462.         /*  Get the real dirID where we're going to put the copy and make sure it is a directory. */
  463.         error = GetDirectoryID(dstVRefNum, dstDirID, dstName, &dstDirID, &isDirectory);
  464.         if ( error != noErr )
  465.         {
  466.             goto ErrorExit;
  467.         }
  468.         if ( !isDirectory )
  469.         {
  470.             error =  dirNFErr;
  471.             goto ErrorExit;
  472.         }
  473.     }
  474.     
  475.     /* Get the real vRefNum of both the source and destination */
  476.     error = DetermineVRefNum(srcName, srcVRefNum, &srcVRefNum);
  477.     if ( error != noErr )
  478.     {
  479.         goto ErrorExit;
  480.     }
  481.     error = DetermineVRefNum(dstName, dstVRefNum, &dstVRefNum);
  482.     if ( error != noErr )
  483.     {
  484.         goto ErrorExit;
  485.     }
  486.     
  487.     if ( preflight )
  488.     {
  489.         error = PreflightDirectoryCopySpace(srcVRefNum, srcDirID, dstVRefNum, copyFilterProc, &spaceOK);
  490.         if ( error != noErr )
  491.         {
  492.             goto ErrorExit;
  493.         }
  494.         if ( !spaceOK )
  495.         {
  496.             error = dskFulErr; /* not enough room on destination */
  497.             goto ErrorExit;
  498.         }
  499.     }
  500.  
  501.     /* Create the new directory in the destination directory with the */
  502.     /* same name as the source directory. */
  503.     error = GetDirName(srcVRefNum, srcDirID, srcDirName);
  504.     if ( error != noErr )
  505.     {
  506.         goto ErrorExit;
  507.     }
  508.     
  509.     /* Again, special case destination if the destination is the */
  510.     /* root parent directory. This time, we'll rename the disk to */
  511.     /* the source directory name. */
  512.     if ( dstDirID == fsRtParID )
  513.     {
  514.         /* Get the current name of the destination disk */
  515.         error = GetDirName(dstVRefNum, fsRtDirID, oldDiskName);
  516.         if ( error == noErr )    
  517.         {
  518.             /* Shorten the name if it's too long to be the volume name */
  519.             TruncPString(srcDirName, srcDirName, 27);
  520.             
  521.             /* Rename the disk */
  522.             error = HRename(dstVRefNum, fsRtParID, oldDiskName, srcDirName);
  523.             /* and copy to the root directory */
  524.             dstDirID = fsRtDirID;
  525.         }
  526.     }
  527.     else
  528.     {
  529.         error = DirCreate(dstVRefNum, dstDirID, srcDirName, &dstDirID);
  530.     }
  531.     if ( error != noErr )
  532.     {
  533.         /* handle any errors from DirCreate */
  534.         if ( copyErrHandler != NULL )
  535.         {
  536.             if ( CallCopyErrProc(copyErrHandler, error, dirCreateOp,
  537.                                                     srcVRefNum, srcDirID, NULL,
  538.                                                     dstVRefNum, dstDirID, srcDirName) )
  539.             {
  540.                 goto ErrorExit;
  541.             }
  542.             else
  543.             {
  544.                 /* If the CopyErrProc handled the problem, clear the error here */
  545.                 /* and continue */
  546.                 error = noErr;
  547.             }
  548.         }
  549.         else
  550.         {
  551.             /* If you don't handle the errors with an error handler, */
  552.             /* then the copy stops here. */
  553.             goto ErrorExit;
  554.         }
  555.     }
  556.     
  557.     /* dstDirID is now the newly created directory! */
  558.         
  559.     /* Set up the globals we need to access from the recursive routine. */
  560.     theGlobals.copyBuffer = (Ptr)copyBufferPtr;
  561.     theGlobals.bufferSize = copyBufferSize;
  562.     theGlobals.destinationVRefNum = dstVRefNum; /* so we can get to it always */
  563.     theGlobals.myCPB.hFileInfo.ioNamePtr = (StringPtr)&theGlobals.itemName;
  564.     theGlobals.myCPB.hFileInfo.ioVRefNum = srcVRefNum;
  565.     theGlobals.errorHandler = copyErrHandler;
  566.     theGlobals.bailout = false;
  567.     theGlobals.copyFilterProc =  copyFilterProc;
  568.         
  569.     /* Here we go into recursion land... */
  570.     CopyLevel(srcDirID, dstDirID, &theGlobals);
  571.     error = theGlobals.error;    /* get the result */
  572.     
  573.     if ( !theGlobals.bailout )
  574.     {
  575.         /* Copy comment from source to destination directory. */
  576.         /* Ignore the result because we really don't care if it worked or not. */
  577.         (void) DTCopyComment(srcVRefNum, srcDirID, NULL, dstVRefNum, dstDirID, NULL);
  578.         
  579.         /* Copy the File Manager attributes */
  580.         error = CopyFileMgrAttributes(srcVRefNum, srcDirID, NULL,
  581.                     dstVRefNum, dstDirID, NULL, true);
  582.         
  583.         /* handle any errors from CopyFileMgrAttributes */
  584.         if ( (error != noErr) && (copyErrHandler != NULL) )
  585.         {
  586.             theGlobals.bailout = CallCopyErrProc(copyErrHandler, error, copyDirFMAttributesOp,
  587.                                                 srcVRefNum, srcDirID, NULL,
  588.                                                 dstVRefNum, dstDirID, NULL);
  589.         }
  590.     }
  591.  
  592. ErrorExit:
  593.     /* Get rid of the copy buffer if we allocated it. */
  594.     if ( ourCopyBuffer )
  595.     {
  596.         DisposePtr((Ptr)copyBufferPtr);
  597.     }
  598.  
  599.     return ( error );
  600. }
  601.  
  602. /*****************************************************************************/
  603.  
  604. pascal    OSErr    DirectoryCopy(short srcVRefNum,
  605.                               long srcDirID,
  606.                               ConstStr255Param srcName,
  607.                               short dstVRefNum,
  608.                               long dstDirID,
  609.                               ConstStr255Param dstName,
  610.                               void *copyBufferPtr,
  611.                               long copyBufferSize,
  612.                               Boolean preflight,
  613.                               CopyErrProcPtr copyErrHandler)
  614. {
  615.     return ( FilteredDirectoryCopy(srcVRefNum, srcDirID, srcName,
  616.                                    dstVRefNum, dstDirID, dstName,
  617.                                    copyBufferPtr, copyBufferSize, preflight,
  618.                                    copyErrHandler, NULL) );
  619. }
  620.  
  621. /*****************************************************************************/
  622.  
  623. pascal    OSErr    FSpFilteredDirectoryCopy(const FSSpec *srcSpec,
  624.                                          const FSSpec *dstSpec,
  625.                                          void *copyBufferPtr,
  626.                                          long copyBufferSize,
  627.                                          Boolean preflight,
  628.                                          CopyErrProcPtr copyErrHandler,
  629.                                          CopyFilterProcPtr copyFilterProc)
  630. {
  631.     return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
  632.                                    dstSpec->vRefNum, dstSpec->parID, dstSpec->name,
  633.                                    copyBufferPtr, copyBufferSize, preflight,
  634.                                    copyErrHandler, copyFilterProc) );
  635. }
  636.  
  637. /*****************************************************************************/
  638.  
  639. pascal    OSErr    FSpDirectoryCopy(const FSSpec *srcSpec,
  640.                                  const FSSpec *dstSpec,
  641.                                  void *copyBufferPtr,
  642.                                  long copyBufferSize,
  643.                                  Boolean preflight,
  644.                                  CopyErrProcPtr copyErrHandler)
  645. {
  646.     return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
  647.                                    dstSpec->vRefNum, dstSpec->parID, dstSpec->name,
  648.                                    copyBufferPtr, copyBufferSize, preflight,
  649.                                    copyErrHandler, NULL) );
  650. }
  651.  
  652. /*****************************************************************************/
  653.  
  654.